package com.global.emc.spring.http.converter;

import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.core.convert.ConversionService;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.DataBinder;

/**
 * 
 * @Description: [application/x-www-form-urlencoded类型form转换为object]
 * @Author: [Joly]
 * @CreateDate: [2013年12月19日 下午5:20:33]
 * @UpdateUser: [Joly]
 * @UpdateDate: [2013年12月19日 下午5:20:33]
 * @UpdateRemark: [说明本次修改内容]
 * @Version: [v1.0]
 * 
 */
public class FormToObjectHttpMessageConverter implements HttpMessageConverter<Object> {
	
	private Charset charset = Charset.forName("UTF-8");
	private ConversionService conversionService;
	private List<MediaType> supportedMediaTypes = new ArrayList<MediaType>();

	public void setSupportedMediaTypes(List<MediaType> supportedMediaTypes) {
		this.supportedMediaTypes = supportedMediaTypes;
	}
	public void setConversionService(ConversionService conversionService) {
		this.conversionService = conversionService;
	}


	@Override
	public List<MediaType> getSupportedMediaTypes() {
		return Collections.unmodifiableList(this.supportedMediaTypes);
	}

	public FormToObjectHttpMessageConverter() {
		this.supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
		this.supportedMediaTypes.add(MediaType.MULTIPART_FORM_DATA);
	}

	@Override
	public boolean canRead(Class<?> clazz, MediaType mediaType) {
		if (MultiValueMap.class.isAssignableFrom(clazz)) {
			return false;
		}
		if (mediaType == null) {
			return true;
		}
		for (MediaType supportedMediaType : getSupportedMediaTypes()) {
			if (!supportedMediaType.equals(MediaType.MULTIPART_FORM_DATA)&& supportedMediaType.includes(mediaType)) {
				return true;
			}
		}
		return false;
	}

	@Override
	public boolean canWrite(Class<?> clazz, MediaType mediaType) {
		if (MultiValueMap.class.isAssignableFrom(clazz)) {
			return false;
		}
		if (mediaType == null || MediaType.ALL.equals(mediaType)) {
			return true;
		}
		for (MediaType supportedMediaType : getSupportedMediaTypes()) {
			if (supportedMediaType.isCompatibleWith(mediaType)) {
				return true;
			}
		}
		return false;
	}

	@Override
	public Object read(Class<? extends Object> clazz,HttpInputMessage inputMessage) throws IOException,HttpMessageNotReadableException {
		MediaType contentType = inputMessage.getHeaders().getContentType();
		Charset charset = contentType.getCharSet() != null ? contentType.getCharSet() : this.charset;
		String body = StreamUtils.copyToString(inputMessage.getBody(), charset);

		String[] pairs = StringUtils.tokenizeToStringArray(body, "&");

		Map<String, String> result = new HashMap<String, String>(pairs.length);

		for (String pair : pairs) {
			int idx = pair.indexOf('=');
			if (idx == -1) {
				result.put(URLDecoder.decode(pair, charset.name()), null);
			} else {
				String name = URLDecoder.decode(pair.substring(0, idx),charset.name());
				String value = URLDecoder.decode(pair.substring(idx + 1),charset.name());
				result.put(name, value);
			}
		}
		DataBinder binder = new DataBinder(BeanUtils.instantiateClass(clazz));
		binder.setConversionService(conversionService);
		MutablePropertyValues mpvs = new MutablePropertyValues(result);
		binder.bind(mpvs);
		
		return binder.getTarget();
	}

	@Override
	public void write(Object t, MediaType contentType,HttpOutputMessage outputMessage) throws IOException,HttpMessageNotWritableException {

	}
	
}
